home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / source.exe / POSIX / MAKE / STR.C < prev    next >
C/C++ Source or Header  |  1992-09-18  |  9KB  |  344 lines

  1. /*-
  2.  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
  3.  * Copyright (c) 1988, 1989 by Adam de Boor
  4.  * Copyright (c) 1989 by Berkeley Softworks
  5.  * All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Adam de Boor.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *    This product includes software developed by the University of
  21.  *    California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #ifdef DF_POSIX
  40. #include <misc.h>
  41. #include <bsdlib.h>
  42. #endif                /* not lint */
  43. #ifndef lint
  44. static char     sccsid[] = "@(#)str.c    5.8 (Berkeley) 6/1/90";
  45. #endif                /* not lint */
  46.  
  47. #include "make.h"
  48.  
  49. /*-
  50.  * str_concat --
  51.  *    concatenate the two strings, inserting a space or slash between them,
  52.  *    freeing them if requested.
  53.  *
  54.  * returns --
  55.  *    the resulting string in allocated space.
  56.  */
  57. char *
  58. str_concat(s1, s2, flags)
  59.     char *s1, *s2;
  60.     int flags;
  61. {
  62.     register int len1, len2;
  63.     register char *result;
  64.  
  65.     /* get the length of both strings */
  66.     len1 = strlen(s1);
  67.     len2 = strlen(s2);
  68.  
  69.     /* allocate length plus separator plus EOS */
  70.     result = emalloc((u_int)(len1 + len2 + 2));
  71.  
  72.     /* copy first string into place */
  73.     bcopy(s1, result, len1);
  74.  
  75.     /* add separator character */
  76.     if (flags & STR_ADDSPACE) {
  77.         result[len1] = ' ';
  78.         ++len1;
  79.     } else if (flags & STR_ADDSLASH) {
  80.         result[len1] = '/';
  81.         ++len1;
  82.     }
  83.  
  84.     /* copy second string plus EOS into place */
  85.     bcopy(s2, result + len1, len2 + 1);
  86.  
  87.     /* free original strings */
  88.     if (flags & STR_DOFREE) {
  89.         (void)free(s1);
  90.         (void)free(s2);
  91.     }
  92.     return(result);
  93. }
  94.  
  95. /*-
  96.  * brk_string --
  97.  *    Fracture a string into an array of words (as delineated by tabs or
  98.  *    spaces) taking quotation marks into account.  Leading tabs/spaces
  99.  *    are ignored.
  100.  *
  101.  * returns --
  102.  *    Pointer to the array of pointers to the words.  To make life easier,
  103.  *    the first word is always the value of the .MAKE variable.
  104.  */
  105. char **
  106. brk_string(str, store_argc)
  107.     register char *str;
  108.     int *store_argc;
  109. {
  110.     static int argmax, curlen;
  111.     static char **argv, *buf;
  112.     register int argc, ch;
  113.     register char inquote, *p, *start, *t;
  114.     int len;
  115.  
  116.     /* save off pmake variable */
  117.     if (!argv) {
  118.         argv = (char **)emalloc((argmax = 50) * sizeof(char *));
  119.         argv[0] = Var_Value(".MAKE", VAR_GLOBAL);
  120.     }
  121.  
  122.     /* skip leading space chars.
  123.     for (; *str == ' ' || *str == '\t'; ++str);
  124.  
  125.     /* allocate room for a copy of the string */
  126.     if ((len = strlen(str) + 1) > curlen)
  127.         buf = emalloc(curlen = len);
  128.  
  129.     /*
  130.      * copy the string; at the same time, parse backslashes,
  131.      * quotes and build the argument list.
  132.      */
  133.     argc = 1;
  134.     inquote = '\0';
  135.     for (p = str, start = t = buf;; ++p) {
  136.         switch(ch = *p) {
  137.         case '"':
  138.         case '\'':
  139.             if (inquote)
  140.                 if (inquote == ch)
  141.                     inquote = NULL;
  142.                 else
  143.                     break;
  144.             else
  145.                 inquote = ch;
  146.             continue;
  147.         case ' ':
  148.         case '\t':
  149.             if (inquote)
  150.                 break;
  151.             if (!start)
  152.                 continue;
  153.             /* FALLTHROUGH */
  154.         case '\n':
  155.         case '\0':
  156.             /*
  157.              * end of a token -- make sure there's enough argv
  158.              * space and save off a pointer.
  159.              */
  160.             *t++ = '\0';
  161.             if (argc == argmax) {
  162.                 argmax *= 2;        /* ramp up fast */
  163.                 if (!(argv = (char **)realloc(argv,
  164.                     argmax * sizeof(char *))))
  165.                 enomem();
  166.             }
  167.             argv[argc++] = start;
  168.             start = (char *)NULL;
  169.             if (ch == '\n' || ch == '\0')
  170.                 goto done;
  171.             continue;
  172.         case '\\':
  173.             switch (ch = *++p) {
  174.             case '\0':
  175.             case '\n':
  176.                 /* hmmm; fix it up as best we can */
  177.                 ch = '\\';
  178.                 --p;
  179.                 break;
  180.             case 'b':
  181.                 ch = '\b';
  182.                 break;
  183.             case 'f':
  184.                 ch = '\f';
  185.                 break;
  186.             case 'n':
  187.                 ch = '\n';
  188.                 break;
  189.             case 'r':
  190.                 ch = '\r';
  191.                 break;
  192.             case 't':
  193.                 ch = '\t';
  194.                 break;
  195.             }
  196.             break;
  197.         }
  198.         if (!start)
  199.             start = t;
  200.         *t++ = ch;
  201.     }
  202. done:    argv[argc] = (char *)NULL;
  203.     *store_argc = argc;
  204.     return(argv);
  205. }
  206.  
  207. /*
  208.  * Str_FindSubstring -- See if a string contains a particular substring.
  209.  * 
  210.  * Results: If string contains substring, the return value is the location of
  211.  * the first matching instance of substring in string.  If string doesn't
  212.  * contain substring, the return value is NULL.  Matching is done on an exact
  213.  * character-for-character basis with no wildcards or special characters.
  214.  * 
  215.  * Side effects: None.
  216.  */
  217. char *
  218. Str_FindSubstring(string, substring)
  219.     register char *string;        /* String to search. */
  220.     char *substring;        /* Substring to find in string */
  221. {
  222.     register char *a, *b;
  223.  
  224.     /*
  225.      * First scan quickly through the two strings looking for a single-
  226.      * character match.  When it's found, then compare the rest of the
  227.      * substring.
  228.      */
  229.  
  230.     for (b = substring; *string != 0; string += 1) {
  231.         if (*string != *b)
  232.             continue;
  233.         a = string;
  234.         for (;;) {
  235.             if (*b == 0)
  236.                 return(string);
  237.             if (*a++ != *b++)
  238.                 break;
  239.         }
  240.         b = substring;
  241.     }
  242.     return((char *) NULL);
  243. }
  244.  
  245. /*
  246.  * Str_Match --
  247.  * 
  248.  * See if a particular string matches a particular pattern.
  249.  * 
  250.  * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
  251.  * matching operation permits the following special characters in the
  252.  * pattern: *?\[] (see the man page for details on what these mean).
  253.  * 
  254.  * Side effects: None.
  255.  */
  256. Str_Match(string, pattern)
  257.     register char *string;        /* String */
  258.     register char *pattern;        /* Pattern */
  259. {
  260.     char c2;
  261.  
  262.     for (;;) {
  263.         /*
  264.          * See if we're at the end of both the pattern and the
  265.          * string. If, we succeeded.  If we're at the end of the
  266.          * pattern but not at the end of the string, we failed.
  267.          */
  268.         if (*pattern == 0)
  269.             return(!*string);
  270.         if (*string == 0 && *pattern != '*')
  271.             return(0);
  272.         /*
  273.          * Check for a "*" as the next pattern character.  It matches
  274.          * any substring.  We handle this by calling ourselves
  275.          * recursively for each postfix of string, until either we
  276.          * match or we reach the end of the string.
  277.          */
  278.         if (*pattern == '*') {
  279.             pattern += 1;
  280.             if (*pattern == 0)
  281.                 return(1);
  282.             while (*string != 0) {
  283.                 if (Str_Match(string, pattern))
  284.                     return(1);
  285.                 ++string;
  286.             }
  287.             return(0);
  288.         }
  289.         /*
  290.          * Check for a "?" as the next pattern character.  It matches
  291.          * any single character.
  292.          */
  293.         if (*pattern == '?')
  294.             goto thisCharOK;
  295.         /*
  296.          * Check for a "[" as the next pattern character.  It is
  297.          * followed by a list of characters that are acceptable, or
  298.          * by a range (two characters separated by "-").
  299.          */
  300.         if (*pattern == '[') {
  301.             ++pattern;
  302.             for (;;) {
  303.                 if ((*pattern == ']') || (*pattern == 0))
  304.                     return(0);
  305.                 if (*pattern == *string)
  306.                     break;
  307.                 if (pattern[1] == '-') {
  308.                     c2 = pattern[2];
  309.                     if (c2 == 0)
  310.                         return(0);
  311.                     if ((*pattern <= *string) &&
  312.                         (c2 >= *string))
  313.                         break;
  314.                     if ((*pattern >= *string) &&
  315.                         (c2 <= *string))
  316.                         break;
  317.                     pattern += 2;
  318.                 }
  319.                 ++pattern;
  320.             }
  321.             while ((*pattern != ']') && (*pattern != 0))
  322.                 ++pattern;
  323.             goto thisCharOK;
  324.         }
  325.         /*
  326.          * If the next pattern character is '/', just strip off the
  327.          * '/' so we do exact matching on the character that follows.
  328.          */
  329.         if (*pattern == '\\') {
  330.             ++pattern;
  331.             if (*pattern == 0)
  332.                 return(0);
  333.         }
  334.         /*
  335.          * There's no special character.  Just make sure that the
  336.          * next characters of each string match.
  337.          */
  338.         if (*pattern != *string)
  339.             return(0);
  340. thisCharOK:    ++pattern;
  341.         ++string;
  342.     }
  343. }
  344.